use crate::gen_title;

pub fn ch2_10_1() {
    gen_title("ch2_10_1", 18);

    #[derive(Debug)]
    struct User {
        active: bool,
        username: String,
        email: String,
        sign_in_count: u64,
    }

    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };

    dbg!(user1);
}

pub fn ch2_10_2() {
    gen_title("ch2_10_2", 18);

    #[derive(Debug)]
    struct User {
        active: bool,
        username: String,
        email: String,
        sign_in_count: u64,
    }

    let mut user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };

    user1.email = String::from("anotheremail@example.com");

    println!("user1: {:?}", user1);
}

pub fn ch2_10_3() {
    gen_title("ch2_10_3", 18);

    #[derive(Debug)]
    struct User {
        active: bool,
        username: String,
        email: String,
        sign_in_count: u64,
    }

    fn build_user(email: String, username: String) -> User {
        User {
            email: email,
            username: username,
            active: true,
            sign_in_count: 1,
        }
    }

    fn build_user_simple(email: String, username: String) -> User {
        User {
            email,
            username,
            active: true,
            sign_in_count: 1,
        }
    }

    let user1 = build_user("example_email@email.com".to_string(), "user1".to_string());
    let user2 = build_user_simple("example_email@email.com".to_string(), "user2".to_string());

    println!("user1: {:?}", user1);
    println!("user2: {:?}", user2);
}

pub fn ch2_10_4() {
    gen_title("ch2_10_4", 18);

    #[derive(Debug)]
    struct User {
        active: bool,
        username: String,
        email: String,
        sign_in_count: u64,
    }

    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };
    println!("user1: {:?}", user1);

    let user2 = User {
        active: user1.active,
        username: user1.username,
        email: String::from("another@example.com"),
        sign_in_count: user1.sign_in_count,
    };
    println!("user2: {:?}", user2);

    let user3 = User {
        email: String::from("another@example.com"),
        ..user2
    };
    println!("user3: {:?}", user3);
}

pub fn ch2_10_5() {
    gen_title("ch2_10_5", 18);

    #[derive(Debug)]
    struct User {
        active: bool,
        username: String,
        email: String,
        sign_in_count: u64,
    }

    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };
    let user2 = User {
        active: user1.active,
        username: user1.username,
        email: String::from("another@example.com"),
        sign_in_count: user1.sign_in_count,
    };

    println!("{}", user1.active);
    println!("{}", user2.active);
}

pub fn ch2_10_6() {
    gen_title("ch2_10_6", 18);

    #[derive(Debug)]
    struct File {
        name: String,
        data: Vec<u8>,
    }

    let f1 = File {
        name: String::from("f1.txt"),
        data: Vec::new(),
    };

    let f1_name = &f1.name;
    let f1_length = &f1.data.len();

    println!("{:?}", f1);
    println!("{} is {} bytes long", f1_name, f1_length);
}

pub fn ch2_10_7() {
    gen_title("ch2_10_7", 18);

    #[derive(Debug)]
    struct Color(i32, i32, i32);

    #[derive(Debug)]
    struct Point(i32, i32, i32);

    let black = Color(0, 0, 0);
    let origin = Point(0, 0, 0);

    println!("{:?}", black);
    println!("{:?}", origin);
}

pub fn ch2_10_8() {
    gen_title("ch2_10_8", 18);

    #[derive(Debug)]
    struct AlwaysEqual;

    let subject = AlwaysEqual;

    println!("{:?}", subject);
}

pub fn ch2_10_9() {
    gen_title("ch2_10_9", 18);

    #[derive(Debug)]
    struct User<'a> {
        username: &'a str,
        email: &'a str,
        sign_in_count: u64,
        active: bool,
    }

    let user1 = User {
        email: "someone@example.com",
        username: "someusername123",
        active: true,
        sign_in_count: 1,
    };

    println!("{:?}", user1);
}

pub fn ch2_10_10() {
    gen_title("ch2_10_10", 18);

    #[derive(Debug)]
    struct Rectangle {
        width: u32,
        height: u32,
    }

    let scale = 2;
    let rect1 = Rectangle {
        width: dbg!(30 * scale),
        height: 50,
    };

    println!("{:#?}", rect1);
}

pub fn ch2_10_pra_1() {
    gen_title("ch2_10_pra_1", 18);

    #[derive(Debug)]
    struct Person {
        name: String,
        age: u8,
        hobby: String,
    }

    let age = 30;
    let p = Person {
        name: String::from("sunface"),
        age,
        hobby: "run".to_string(),
    };

    println!("{:?}", p);
}

pub fn ch2_10_pra_2() {
    gen_title("ch2_10_pra_2", 18);

    #[derive(Debug)]
    struct Unit {};

    trait SomeTrait {
        fn print(&self);
    }

    impl SomeTrait for Unit {
        fn print(&self) {
            println!("{:?}, hello", &self);
        }
    }

    fn do_something_with_unit(u: Unit) {
        u.print()
    }

    let u = Unit {};
    do_something_with_unit(u);
}

pub fn ch2_10_pra_3() {
    gen_title("ch2_10_pra_3", 18);

    #[derive(Debug)]
    struct Color(i32, i32, i32);
    #[derive(Debug)]
    struct Point(i32, i32, i32);

    let v = Color(0, 127, 255);
    check_color(v);

    fn check_color(p: Color) {
        let Color(x, y, z) = p;
        assert_eq!(x, 0);
        assert_eq!(p.1, 127);
        assert_eq!(z, 255);
        println!("{:?}", p);
    }
}

pub fn ch2_10_pra_4() {
    gen_title("ch2_10_pra_4", 18);

    #[derive(Debug)]
    struct Person {
        name: String,
        age: u8,
    }

    let age = 18;
    let mut p = Person {
        name: String::from("sunface"),
        age,
    };

    p.age = 30;
    p.name = String::from("sunfei");

    println!("{:?}", p);
}

pub fn ch2_10_pra_5() {
    gen_title("ch2_10_pra_5", 18);

    #[derive(Debug)]
    struct Person {
        name: String,
        age: u8,
    }

    fn build_person(name: String, age: u8) -> Person {
        Person { name, age }
    }

    let p = build_person("sunface".to_string(), 28);
    println!("{:?}", p);
}

pub fn ch2_10_pra_6() {
    gen_title("ch2_10_pra_6", 18);

    #[derive(Debug)]
    struct User {
        active: bool,
        username: String,
        email: String,
        sign_in_count: u64,
    }

    let u1 = User {
        email: String::from("someone@example.com"),
        username: String::from("sunface"),
        active: true,
        sign_in_count: 1,
    };

    let u2 = set_email(u1);

    println!("{:?}", u2);

    fn set_email(u: User) -> User {
        User {
            email: String::from("contact@im.dev"),
            ..u
        }
    }
}

pub fn ch2_10_pra_7() {
    gen_title("ch2_10_pra_7", 18);

    #[derive(Debug)]
    struct Person {
        name: String,
        age: Box<u8>,
    }

    let person = Person {
        name: String::from("Alice"),
        age: Box::new(20),
    };

    let Person { name, ref age } = person;
    println!("The person's age is {}", age);
    println!("The person's name is {}", name);

    println!("The person's age from person struct is {}", person.age);
}

pub fn ch2_10_pra_8() {
    gen_title("ch2_10_pra_8", 18);

    #[derive(Debug)]
    struct File {
        name: String,
        data: String,
    }

    let f = File {
        name: String::from("readme.md"),
        data: "Rust By Practice".to_string(),
    };

    let _name = &f.name;
    println!("{}", _name);
    print!("{}, {}, {:?}", f.name, f.data, f);
}
